package namespaces

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"pkg/sandbox/seccomp"
	"strings"
	"syscall"
)

// NamespaceConfig 定义命名空间配置选项
type NamespaceConfig struct {
	UTS    bool   // 隔离主机名和域名
	PID    bool   // 隔离进程ID
	User   bool   // 隔离用户和用户组ID
	Mount  bool   // 隔离文件系统挂载点
	IPC    bool   // 隔离信号量、消息队列、共享内存和POSIX消息队列
	Net    bool   // 隔离网络设备、网络栈、端口等
	RootFS string // 新的根文件系统路径(chroot)
}

// NamespaceManager 管理进程的命名空间隔离
type NamespaceManager struct {
	config        *NamespaceConfig
	cmd           *exec.Cmd
	syncPipe      *os.File
	seccompFilter *seccomp.BPFProgram // 添加Seccomp过滤器
}

// NewNamespaceManagerWithSeccomp 创建带有Seccomp支持的命名空间管理器
func NewNamespaceManagerWithSeccomp(config *NamespaceConfig, filter *seccomp.BPFProgram) *NamespaceManager {
	return &NamespaceManager{
		config:        config,
		seccompFilter: filter,
	}
}

// CreateChildProcess 创建子进程并应用安全设置
func (m *NamespaceManager) CreateChildProcess(command string, args []string) error {
	// 创建同步管道
	parentPipe, childPipe, err := os.Pipe()
	if err != nil {
		return fmt.Errorf("failed to create sync pipe: %w", err)
	}
	defer parentPipe.Close()

	// 准备命令 - 使用一个特殊的初始化程序
	m.cmd = exec.Command("/proc/self/exe", "--init-child")

	// 设置命名空间标志
	cloneFlags := m.cloneFlags()
	m.cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: cloneFlags,
		// 暂时不使用chroot，因为需要root权限
	}

	// 设置环境变量传递参数
	m.cmd.Env = append(os.Environ(),
		fmt.Sprintf("SANDBOX_COMMAND=%s", command),
		fmt.Sprintf("SANDBOX_ARGS=%s", strings.Join(args, " ")),
	)

	// 传递同步管道到子进程
	m.cmd.ExtraFiles = []*os.File{childPipe}
	m.syncPipe = parentPipe

	// 启动子进程
	if err := m.cmd.Start(); err != nil {
		return fmt.Errorf("failed to start child process: %w", err)
	}

	// 关闭子进程端的管道
	childPipe.Close()

	// 等待子进程初始化完成
	if err := m.waitForChild(); err != nil {
		m.Cleanup()
		return fmt.Errorf("child process initialization failed: %w", err)
	}

	return nil
}

// GetCommand 获取创建的exec.Cmd
func (m *NamespaceManager) GetCommand() *exec.Cmd {
	return m.cmd
}

// Wait 等待子进程退出
func (m *NamespaceManager) Wait() error {
	return m.cmd.Wait()
}

// Cleanup 清理资源
func (m *NamespaceManager) Cleanup() {
	if m.syncPipe != nil {
		m.syncPipe.Close()
		m.syncPipe = nil
	}

	// 清理命名空间资源
	if m.config.PID && m.cmd != nil && m.cmd.Process != nil {
		// 终止命名空间内的所有进程
		syscall.Kill(-m.cmd.Process.Pid, syscall.SIGKILL)
	}
}

// 初始化子进程环境（在子进程中调用）
func (m *NamespaceManager) InitChildProcess() error {
	// 获取同步管道（文件描述符3）
	pipe := os.NewFile(3, "syncPipe")
	defer pipe.Close()

	// 应用Seccomp过滤器（如果需要）
	if m.seccompFilter != nil {
		if err := m.seccompFilter.ApplyToCurrentProcess(); err != nil {
			return notifyParent(pipe, fmt.Errorf("seccomp apply failed: %w", err))
		}
	}

	// 设置主机名（UTS命名空间）
	if m.config.UTS {
		if err := syscall.Sethostname([]byte("sandbox")); err != nil {
			return notifyParent(pipe, err)
		}
	}

	// 根文件系统已经在父进程中通过chroot设置

	// 挂载proc文件系统（PID命名空间）
	if m.config.PID {
		if err := syscall.Mount("proc", "/proc", "proc", 0, ""); err != nil {
			return notifyParent(pipe, fmt.Errorf("failed to mount proc: %w", err))
		}
	}

	// 通知父进程初始化成功
	if _, err := pipe.Write([]byte{0}); err != nil {
		return fmt.Errorf("failed to notify parent: %w", err)
	}

	return nil
}

// 生成命名空间的clone标志位
func (m *NamespaceManager) cloneFlags() uintptr {
	var flags uintptr

	if m.config.UTS {
		flags |= syscall.CLONE_NEWUTS
	}
	if m.config.PID {
		flags |= syscall.CLONE_NEWPID
	}
	if m.config.User {
		flags |= syscall.CLONE_NEWUSER
	}
	if m.config.Mount {
		flags |= syscall.CLONE_NEWNS
	}
	if m.config.IPC {
		flags |= syscall.CLONE_NEWIPC
	}
	if m.config.Net {
		flags |= syscall.CLONE_NEWNET
	}

	return flags
}

// 设置新的根文件系统
func (m *NamespaceManager) setupRootFS() error {
	// 确保根文件系统存在
	if _, err := os.Stat(m.config.RootFS); os.IsNotExist(err) {
		return fmt.Errorf("rootfs path does not exist: %s", m.config.RootFS)
	}

	// 创建临时目录用于pivot_root
	pivotDir := filepath.Join(m.config.RootFS, ".pivot_root")
	if err := os.Mkdir(pivotDir, 0700); err != nil && !os.IsExist(err) {
		return fmt.Errorf("failed to create pivot_root dir: %w", err)
	}

	// 挂载根文件系统
	if err := syscall.Mount(m.config.RootFS, m.config.RootFS, "", syscall.MS_BIND|syscall.MS_REC, ""); err != nil {
		return fmt.Errorf("failed to bind mount rootfs: %w", err)
	}

	// 切换到新的根文件系统
	if err := syscall.PivotRoot(m.config.RootFS, pivotDir); err != nil {
		return fmt.Errorf("pivot_root failed: %w", err)
	}

	// 切换到新的根目录
	if err := syscall.Chdir("/"); err != nil {
		return fmt.Errorf("chdir failed: %w", err)
	}

	// 卸载旧的根文件系统
	if err := syscall.Unmount("/.pivot_root", syscall.MNT_DETACH); err != nil {
		return fmt.Errorf("unmount pivot_root failed: %w", err)
	}

	// 删除临时目录
	if err := os.Remove("/.pivot_root"); err != nil {
		return fmt.Errorf("remove pivot_root failed: %w", err)
	}

	return nil
}

// 等待子进程完成初始化
func (m *NamespaceManager) waitForChild() error {
	// 读取子进程发来的初始化状态
	status := make([]byte, 1)
	_, err := m.syncPipe.Read(status)
	if err != nil {
		return fmt.Errorf("failed to read sync status: %w", err)
	}

	if status[0] != 0 {
		return fmt.Errorf("child initialization failed with code %d", status[0])
	}

	return nil
}

// 通知父进程初始化状态
func notifyParent(pipe *os.File, err error) error {
	code := byte(1)
	if err == nil {
		code = 0
	} else {
		fmt.Fprintf(os.Stderr, "Child init error: %v\n", err)
	}

	if _, writeErr := pipe.Write([]byte{code}); writeErr != nil {
		return fmt.Errorf("failed to notify parent: %w (original error: %v)", writeErr, err)
	}

	return err
}
